import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Map
{
	private HashMap<Position, CellType> _map;
	private HashSet<Position> _visited;
	private int _width;
	private int _height;
	
	public int getWidth()
	{
		return _width;
	}
	public int getHeight()
	{
		return _height;
	}
	
	public Map(Collection<String> percepts)
	{
		_map = new HashMap<Position, CellType>();
		_visited = new HashSet<Position>();
		
		Pattern perceptNamePattern = Pattern.compile("\\(\\s*([^\\s]+).*");
		for (String percept:percepts) 
		{
			Matcher perceptNameMatcher = perceptNamePattern.matcher(percept);
			if (perceptNameMatcher.matches()) 
			{
				String perceptName = perceptNameMatcher.group(1);
	
				if (perceptName.equals("HOME")) 
				{
					Matcher m = Pattern.compile("\\(\\s*HOME\\s+([0-9]+)\\s+([0-9]+)\\s*\\)").matcher(percept);
					if (m.matches()) 
					{
						int x = Integer.parseInt(m.group(1))-1, y = Integer.parseInt(m.group(2))-1;
						setAt(new Position(x, y), CellType.Home);
					}
				}
				else if (perceptName.equals("ORIENTATION"))
				{
					//do nothing
				}
				else if (perceptName.equals("AT"))
				{
					Matcher m = Pattern.compile("\\(\\s*(AT)\\s+(DIRT|OBSTACLE)\\s+([0-9]+)\\s+([0-9]+)\\s*\\)").matcher(percept);
					if (m.matches()) 
					{
						int x = Integer.parseInt(m.group(3))-1, y = Integer.parseInt(m.group(4))-1;
						Position pos = new Position(x, y);
						if (m.group(2).equals("DIRT"))
						{
							setAt(pos, CellType.Dirty);
						}
						else
						{
							setAt(pos, CellType.Wall);
						}
					}
				}
				else if (perceptName.equals("SIZE"))
				{
					Matcher m = Pattern.compile("\\(\\s*SIZE\\s+([0-9]+)\\s+([0-9]+)\\s*\\)").matcher(percept);
					if (m.matches())
					{
						_width = Integer.parseInt(m.group(1));
						_height = Integer.parseInt(m.group(2));
						
					}
				}
				else 
				{
					System.out.println("other percept:" + percept);
				}
			} 
			else 
			{
				System.err.println("strange percept that does not match pattern: " + percept);
			}
		}
	}
	private void setAt(Position pos, CellType cell)
	{
		_map.put(pos, cell);
	}
	public CellType getAt(Position pos)
	{
		if(pos.x < 0 || pos.y < 0 || pos.x >= _width || pos.y >= _height)
		{
			return CellType.Wall;
		}
		else if(_map.containsKey(pos))
		{
			return _map.get(pos);
		}
		else return CellType.Empty;
	}
	public Position getHomeCell()
	{	
		for(Entry<Position, CellType> entry : _map.entrySet())
		{
			if(entry.getValue() == CellType.Home)
				return entry.getKey();
		}
		
		return new Position(-1,-1);
	}
	public LinkedList<Position> getDirtyCells()
	{
		LinkedList<Position> positions = new LinkedList<Position>();
		
		for(Entry<Position, CellType> entry : _map.entrySet())
		{
			if(entry.getValue() == CellType.Dirty)
				positions.add(entry.getKey());
		}
		
		return positions;
	}
	public Boolean containsDirt()
	{
		for(CellType cell : _map.values())
		{
			if(cell == CellType.Dirty) return true;
		}
		return false;
	}
	public void cleanCellAt(Position pos)
	{
		if(getAt(pos) == CellType.Dirty)
		{
			setAt(pos, CellType.Empty);
		}
	}
	public void clearVisited()
	{
		_visited.clear();
	}
	public void visit(Position pos)
	{
		_visited.add(pos);
	}
	public Boolean hasVisited(Position pos)
	{
		return _visited.contains(pos);
	}
}